/**
 * @Author: wzx
 * @Description:
 * @Version: 1.0.0
 * @Date: 2021/5/17 下午6:58
 *@Copyright: MIN-Group；国家重大科技基础设施——未来网络北大实验室；深圳市信息论与未来网络重点实验室
 */

package network

import (
	"fmt"
	"encoding/json"
	"sync"
	"vpn-management-server/cache"
	"vpn-management-server/config"
	"vpn-management-server/logger"
	"vpn-management-server/security/keymanager"
)

type ConnPool struct {
	ConnMap map[string]Connect
	Mu      sync.Mutex
}

func NewConnPool() *ConnPool {
	return &ConnPool{
		ConnMap: make(map[string]Connect),
	}
}

var DefaultConnPool = NewConnPool()

type Net interface {
	Listen(portOrPrefix string) error
	Listens(portOrPrefix string, sslPortOrPrefix string, key *keymanager.KeyManager) error
	Accept() (Connect, error)
	Dial(host string) (Connect, error)
	Dials(host string, sslHost string, key *keymanager.KeyManager, serverPubKey []byte) (Connect, error)
}

type Connect interface {
	Read() ([]byte, error)
	readSSL() ([]byte, error)
	Write([]byte) error
	write([]byte) error
	GetRemote() string
	Close() error
}

type bcConfig struct {
	bcAddress    string
	bcsslAddress string
	publicKey    string
}

type oaConfig struct {
	oaAddress    string
	oasslAddress string
	publicKey    string
}

type keyConfig struct {
	defaultExpiration int
	cleanupInterval   int
	cachePath         string
}

var bcCfg bcConfig

var oaCfg oaConfig

func Init(config *config.VPNConfig) {
	bcCfg.bcAddress = config.GetBCAddress()
	bcCfg.bcsslAddress = config.GetBCSSLAddress()
	bcCfg.publicKey = config.BCSSLConfig.Pubkey

	secKeyCache = cache.NewWithPath("secKey", config.KeyConfig.DefaultExpiration, config.KeyConfig.CleanupInterval, config.KeyConfig.CachePath)
}

func GetBCSSLConn() Connect {
	var bcnet TCPNet
	var key keymanager.KeyManager
	key.GenKeyPair()
	conn, err := bcnet.Dials(bcCfg.bcAddress, bcCfg.bcsslAddress, &key, []byte(bcCfg.publicKey))
	fmt.Println(bcCfg.bcAddress, bcCfg.bcsslAddress)
	if err != nil {
		logger.Logger.Error("dail error:", err.Error())
		return nil
	}

	return conn
}

func SendRequest(request *NetRequest, conn Connect) error {
	b, _ := json.Marshal(request)
	err := conn.Write(b)
	if err != nil {
		logger.Logger.Error("Error send message", err.Error())
		return err
	}

	return nil
}

func GetResponse(conn Connect) (*NetResponse, error) {
	buf, err := conn.Read()
	if err != nil {
		logger.Logger.Error("Error Reading", err.Error())
		return nil, err
	}

	var response NetResponse
	err = json.Unmarshal(buf, &response)
	if err != nil {
		logger.Logger.Error("parse response fail", err.Error())
		return nil, err
	}

	return &response, nil
}
